package main

import (
	"io"
	"os"
	"runtime"
	"sync"
	"time"

	"gitee.com/Luna-CY/Golang-Project-Template/internal/context"
	"gitee.com/Luna-CY/Golang-Project-Template/internal/context/contextutil"
	"gitee.com/Luna-CY/Golang-Project-Template/internal/interface/dao"
	"gitee.com/Luna-CY/Golang-Project-Template/internal/interface/service"
	"gitee.com/Luna-CY/Golang-Project-Template/internal/logger"
	"gitee.com/Luna-CY/Golang-Project-Template/internal/util/timer"
	"gitee.com/Luna-CY/Golang-Project-Template/model"
	"github.com/spf13/cobra"
)

func NewWorkerSendEmailCommand() *cobra.Command {
	var command = &cobra.Command{
		Use:  "send-email",
		Args: cobra.NoArgs,
		Run: func(cmd *cobra.Command, args []string) {
			defer func() {
				cmd.Println("发送邮件任务已停止")
			}()

			cmd.Println("发送邮件任务已启动")

			var ctx = contextutil.NewContextWithStandard(cmd.Context())

			var smtpService = NewSmtpService()

			// 启动处理器

			var wg = sync.WaitGroup{}
			wg.Add(runtime.NumCPU())

			var ch = make(chan *model.SystemSmtpLog, runtime.NumCPU()*10)
			for range runtime.NumCPU() {
				go smtpSendProcessor(ctx, &wg, ch)
			}

			timer.NewMinuteTicker(ctx, func(ctx context.Context, ticker *time.Ticker, now time.Time) {
				cmd.Printf("运行时间: %v\n", now)

				var page = 1
				for {
					_, data, err := smtpService.ListSmtpLogByCondition(ctx, page, 100, dao.SystemSmtpLogOptionWithSendType(model.SystemSmtpLogSendTypeTime), dao.SystemSmtpLogOptionWithSendTimeEqualOrLessThan(now.Unix()))
					if nil != err {
						logger.SugarLogger(logger.WithRequestId(ctx), logger.WithStack()).Errorf("CMC_ND.NWSEC_ND.362850 查询邮件日志失败，错误信息为 %q", err.Error())

						break
					}

					for _, item := range data {
						ch <- item
					}

					if 100 != len(data) {
						break
					}

					page++
				}
			})

			close(ch)
			wg.Wait()
		},
	}

	return command
}

func smtpSendProcessor(ctx context.Context, wg *sync.WaitGroup, ch <-chan *model.SystemSmtpLog) {
	defer wg.Done()

	var storageService = NewStorageService()
	var smtpService = NewSmtpService()

	for smtpLog := range ch {
		attachments, err := smtpService.BatchGetSmtpLogAttachment(ctx, smtpLog)

		if nil != err {
			logger.SugarLogger(logger.WithRequestId(ctx), logger.WithStack()).Errorf("CMC_ND.NWSEC_ND.443015 查询邮件日志附件失败，错误信息为 %q", err.Error())

			continue
		}

		var files []*os.File

		var fail = false
		var reason = ""

		// 下载附件
		for _, attachment := range attachments {
			object, err := storageService.GetObjectByCondition(ctx, dao.SystemObjectOptionWithId(*attachment.ObjectId))
			if nil != err {
				fail = true
				reason = err.Error()
				logger.SugarLogger(logger.WithRequestId(ctx), logger.WithStack()).Errorf("CMC_ND.NWSEC_ND.524224 查询邮件日志附件失败，错误信息为 %q", err.Error())

				break
			}

			reader, err := storageService.DownloadObject(ctx, object)
			if nil != err {
				fail = true
				reason = err.Error()
				logger.SugarLogger(logger.WithRequestId(ctx), logger.WithStack()).Errorf("CMC_ND.NWSEC_ND.604315 下载邮件日志附件失败，错误信息为 %q", err.Error())

				break
			}

			tf, rerr := os.CreateTemp("", "email-attachment-*")
			if nil != rerr {
				fail = true
				reason = rerr.Error()
				logger.SugarLogger(logger.WithRequestId(ctx), logger.WithStack()).Errorf("CMC_ND.NWSEC_ND.684331 创建邮件日志附件临时文件失败，错误信息为 %q", rerr.Error())

				break
			}

			if _, err := io.Copy(tf, reader); nil != err {
				fail = true
				reason = err.Error()
				logger.SugarLogger(logger.WithRequestId(ctx), logger.WithStack()).Errorf("CMC_ND.NWSEC_ND.764340 写入邮件日志附件临时文件失败，错误信息为 %q", err.Error())

				break
			}

			if _, err := tf.Seek(0, io.SeekStart); nil != err {
				fail = true
				reason = err.Error()
				logger.SugarLogger(logger.WithRequestId(ctx), logger.WithStack()).Errorf("CMC_ND.NWSEC_ND.844357 重置邮件日志附件临时文件指针失败，错误信息为 %q", err.Error())

				break
			}

			files = append(files, tf)
		}

		if fail {
			// 删除临时文件
			for _, file := range files {
				file.Close()
				os.Remove(file.Name())
			}

			if err := smtpService.UpdateLog(ctx, smtpLog, service.SystemSmtpLogFieldWithStatus(model.SystemSmtpLogStatusFailed), service.SystemSmtpLogFieldWithFailedReason(reason)); nil != err {
				logger.SugarLogger(logger.WithRequestId(ctx), logger.WithStack()).Errorf("CMC_ND.NWSEC_ND.1064948 更新邮件日志失败，错误信息为 %q", err.Error())
			}

			continue
		}

		// 发送邮件
		if err := smtpService.SendTimeTo(ctx, smtpLog, files); nil != err {
			logger.SugarLogger(logger.WithRequestId(ctx), logger.WithStack()).Errorf("CMC_ND.NWSEC_ND.1135032 发送邮件失败，错误信息为 %q", err.Error())

			if err := smtpService.UpdateLog(ctx, smtpLog, service.SystemSmtpLogFieldWithStatus(model.SystemSmtpLogStatusFailed), service.SystemSmtpLogFieldWithFailedReason(err.Error())); nil != err {
				logger.SugarLogger(logger.WithRequestId(ctx), logger.WithStack()).Errorf("CMC_ND.NWSEC_ND.1165100 更新邮件日志失败，错误信息为 %q", err.Error())
			}
		}

		// 删除临时文件
		for _, file := range files {
			file.Close()
			os.Remove(file.Name())
		}
	}
}
